<!DOCTYPE html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script>

// Copied from resources/bluetooth/bluetooth-helpers.js.
function callWithKeyDown(functionCalledOnKeyPress) {
  return new Promise((resolve, reject) => {
    function onKeyUp() {
      document.removeEventListener('keyup', onKeyUp, false);
      try {
        resolve(functionCalledOnKeyPress());
      } catch (e) {
        reject(e);
      }
    }
    document.addEventListener('keyup', onKeyUp, false);

    eventSender.keyDown('Enter', []);
  });
}

var prompt_test_cases = [
    {
        name: 'prompt-accept-access-userchoice-first',
        cancel: true,
        late: false,
        platform: 'foo',
        outcome: 'accepted',
        userChoice: true
    }, {
        name: 'prompt-accept-no-access-userchoice-first',
        cancel: true,
        late: false,
        platform: 'foo',
        outcome: 'accepted',
        userChoice: false
    }, {
        name: 'prompt-dismiss-access-userchoice-first',
        cancel: true,
        late: false,
        platform: '',
        outcome: 'dismissed',
        userChoice: true
    }, {
        name: 'prompt-dismiss-no-access-userchoice-first',
        cancel: true,
        late: false,
        platform: '',
        outcome: 'dismissed',
        userChoice: false
    }, {
        name: 'prompt-before-preventDefault-access-userchoice-first',
        cancel: false,
        late: false,
        platform: 'foo',
        outcome: 'accepted',
        userChoice: true
    }, {
        name: 'prompt-before-preventDefault-no-access-userchoice-first',
        cancel: false,
        late: false,
        platform: 'foo',
        outcome: 'accepted',
        userChoice: false
    }, {
        name: 'prompt-late-accept-access-userchoice-first',
        cancel: true,
        late: true,
        platform: 'foo',
        outcome: 'accepted',
        userChoice: false
    }, {
        name: 'prompt-late-accept-no-access-userchoice-first',
        cancel: true,
        late: true,
        platform: 'foo',
        outcome: 'accepted',
        userChoice: false
    }, {
        name: 'prompt-late-dismiss-access-userchoice-first',
        cancel: true,
        late: true,
        platform: '',
        outcome: 'dismissed',
        userChoice: true
    }, {
        name: 'prompt-late-dismiss-no-access-userchoice-first',
        cancel: true,
        late: true,
        platform: '',
        outcome: 'dismissed',
        userChoice: false
    }, {
        name: 'prompt-late-without-preventDefault-access-userchoice-first',
        cancel: false,
        late: true,
        platform: '',
        outcome: 'dismissed',
        userChoice: true
    }, {
        name: 'prompt-late-without-preventDefault-no-access-userchoice-first',
        cancel: false,
        late: true,
        platform: '',
        outcome: 'dismissed',
        userChoice: false
    }
];

function verify_prompt_resolve(e, t, test_case) {
    callWithKeyDown(() => e.prompt().then(t.step_func(function(result) {
        assert_equals(result.platform, test_case.platform, 'Resolved platform');
        assert_equals(result.outcome, test_case.outcome, 'Outcome');
    }), t.unreached_func("prompt() promise should resolve.")));
}

function verify_prompt_reject(e, t) {
    e.prompt().then(t.unreached_func("prompt() promise should reject."),
        t.step_func(function(error) {
            assert_true(
                error instanceof DOMException,
                "Rejected promise should throw a DOMException."
            );
            assert_equals(
                error.message,
                "Failed to execute 'prompt' on 'BeforeInstallPromptEvent': " +
                    "The prompt() method must be called with a user gesture",
                "Rejected promise does not provide expected message."
            );
        })
    );
}

function verify_userChoice(e, t, test_case, index) {
    e.userChoice.then(t.step_func(function(result) {
        assert_equals(result.platform, test_case.platform, 'Resolved platform');
        assert_equals(result.outcome, test_case.outcome, 'Outcome');
    })).then(t.step_func(function() {
        prompt_test(index + 1);
        t.done();
    }), t.unreached_func("userChoice promise should resolve."));
}

function prompt_test(index) {
    if (index >= prompt_test_cases.length)
        return;

    var test_case = prompt_test_cases[index];
    async_test(function(t) {
        var event = null;
        var event_handler = t.step_func(function(e) {
            // Remove the event handler to prevent it being used in subsequent
            // invocations of prompt_test(). Save event object for call outside handler.
            window.removeEventListener('beforeinstallprompt', event_handler);
            event = e;

            assert_equals(e.platforms.length, 2, 'Number of platforms');
            assert_equals(e.platforms[0], 'foo', 'First platform');
            assert_equals(e.platforms[1], 'bar', 'Second platform');

            if (test_case.userChoice) {
                // Access userChoice to ensure it is independent of prompt.
                e.userChoice;
            }

            if (test_case.cancel) {
                e.preventDefault();
            }

            if (test_case.late) {
                window.setTimeout(function() {
                    assert_false(event == null, "event is null outside handler");

                    // Test that firing prompt() outside of the handler resolves or rejects correctly.
                    verify_prompt_resolve(event, t, test_case);
                    // Check userChoice and call the next test.
                    verify_userChoice(event, t, test_case, index);
                }, 0);
                return;
            }

            // Ensure prompt rejects without a user gesture.
            verify_prompt_reject(e, t);

            // Call prompt() to restart the pipeline.
            verify_prompt_resolve(e, t, test_case);

            // prompt() has been fired, so check the userChoice promise and call the next test.
            verify_userChoice(e, t, test_case, index);
        });
        window.addEventListener('beforeinstallprompt', event_handler);

        testRunner.dispatchBeforeInstallPromptEvent(['foo', 'bar'], t.step_func(function(result) {
            testRunner.resolveBeforeInstallPromptPromise(test_case.platform);
        }));
    }, test_case.name);
}

prompt_test(0);
</script>
